package com.mtoolkit.property.support;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;

import com.mtoolkit.property.IProperties;
import com.mtoolkit.util.LogUtil;

/**
 * 读取属性文件的抽象类。
 * @version 1.00 2010.12.30, 11:30:16
 * @since 1.6
 * @author ZhangShixi
 */
public abstract class AbstractProperties implements IProperties {

    //---- attributes ----------------------------------------------------------
    //属性文件是否已被载入，默认为false，未被载入。
    private volatile boolean _load = false;
    /**
     * 日志记录器。
     */
    protected static final LogUtil LOGGER = LogUtil.getLogger(IProperties.class);

    //---- public methods ------------------------------------------------------
    /**
     * 通过给定的属性文件的URL来载入属性文件配置信息。
     * @param url 属性文件对应的URL信息。
     * @throws java.io.IOException 加载属性文件异常。
     */
    @Override
    public void load(URL url) throws IOException {
        doLoadProperties(url.getPath());
        _load = true;
    }

    /**
     * 通过给定的属性文件来载入属性文件的配置信息。
     * @param file 属性文件对应File实例。
     * @throws java.io.IOException 加载属性文件异常。
     */
    @Override
    public void load(File file) throws IOException {
        doLoadProperties(file.getPath());
        _load = true;
    }

    /**
     * 通过给定的属性文件的路径来载入属性文件的配置信息。
     * @param filePath 属性文件所在的类路径。
     * @throws java.io.IOException 加载属性文件异常。
     */
    @Override
    public void load(String filePath) throws IOException {
        doLoadProperties(filePath);
        _load = true;
    }

    /**
     * 返回此属性文件是否已被载入。
     * @return 是否已载入。
     *      <code>true</code>表示已载入，<code>false</code>表示未被载入。
     */
    @Override
    public boolean isLoad() {
        return _load;
    }

    /**
     * 获取指定键的属性值。如果此属性值不存在，将使用调用者指定的默认值。
     * @param key 键值对的键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 指定键的属性值。如果此属性值不存在，将使用调用者指定的默认值。
     */
    @Override
    public String getValue(String key, String defaultValue) {
        try {
            return getValue(key);
        } catch (NoSuchElementException ex) {
            return defaultValue;
        }
    }

    /**
     * 获取指定值对应的所有键的列表。
     * @param value 指定的属性值。
     * @return 属性值对应的键列表。
     * @ 获取属性异常。
     */
    @Override
    public List<String> getKey(String value) {
        if (value == null || value.isEmpty()) {
            LOGGER.error("value is null or empty.");
            throw new NullPointerException("value is null or empty.");
        }

        Set<Entry<String, String>> entrySet = entrySet();
        if (entrySet == null || entrySet.isEmpty()) {
            return null;
        }

        List<String> returnKeys = new LinkedList<String>();
        for (Entry<String, String> entry : entrySet) {
            if (entry == null || entry.getKey() == null || entry.getValue() == null) {
                continue;
            }

            if (value.equals(entry.getValue())) {
                returnKeys.add(entry.getKey());
            }
        }

        if (returnKeys.isEmpty()) {
            return Collections.emptyList();
        } else {
            return returnKeys;
        }
    }

    /**
     * 获取指定属性键对应的int基本类型的属性值。
     * @param key 属性键。
     * @return 属性键对应的int类型的属性值。
     * @throws java.util.NoSuchElementException 如果指定的键不存在，将抛出此异常。
     */
    @Override
    public int getIntValue(String key) {
        return Integer.parseInt(getValue(key));
    }

    /**
     * 获取指定属性键对应的int类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的int类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public int getIntValue(String key, int defaultValue) {
        return getIntegerValue(key, Integer.valueOf(defaultValue)).intValue();
    }

    /**
     * 获取指定属性键对应的Integer类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的Integer类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public Integer getIntegerValue(String key, Integer defaultValue) {
        try {
            return Integer.valueOf(getValue(key));
        } catch (NoSuchElementException ex) {
            return defaultValue;
        }
    }

    /**
     * 获取指定属性键对应的long基本类型的属性值。
     * @param key 属性键。
     * @return 属性键对应的long类型的属性值。
     * @throws java.util.NoSuchElementException 如果指定的键不存在，将抛出此异常。
     */
    @Override
    public long getLongValue(String key) {
        return Long.parseLong(getValue(key));
    }

    /**
     * 获取指定属性键对应的long类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的long类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public long getLongValue(String key, long defaultValue) {
        return getLongValue(key, Long.valueOf(defaultValue)).longValue();
    }

    /**
     * 获取指定属性键对应的Long类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的Long类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public Long getLongValue(String key, Long defaultValue) {
        try {
            return Long.valueOf(getValue(key));
        } catch (NoSuchElementException ex) {
            return defaultValue;
        }
    }

    /**
     * 获取指定属性键对应的byte基本类型的属性值。
     * @param key 属性键。
     * @return 属性键对应的byte类型的属性值。
     * @throws java.util.NoSuchElementException 如果指定的键不存在，将抛出此异常。
     */
    @Override
    public byte getByteValue(String key) {
        return Byte.parseByte(getValue(key));
    }

    /**
     * 获取指定属性键对应的byte类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的byte类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public byte getByteValue(String key, byte defaultValue) {
        return getByteValue(key, Byte.valueOf(defaultValue)).byteValue();
    }

    /**
     * 获取指定属性键对应的Byte类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的Byte类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public Byte getByteValue(String key, Byte defaultValue) {
        try {
            return Byte.valueOf(getValue(key));
        } catch (NoSuchElementException ex) {
            return defaultValue;
        }
    }

    /**
     * 获取指定属性键对应的double基本类型的属性值。
     * @param key 属性键。
     * @return 属性键对应的double类型的属性值。
     * @throws java.util.NoSuchElementException 如果指定的键不存在，将抛出此异常。
     */
    @Override
    public double getDoubleValue(String key) {
        return Double.parseDouble(getValue(key));
    }

    /**
     * 获取指定属性键对应的double类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的double类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public double getDoubleValue(String key, double defaultValue) {
        return getDoubleValue(key, Double.valueOf(defaultValue)).doubleValue();
    }

    /**
     * 获取指定属性键对应的Double类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的Double类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public Double getDoubleValue(String key, Double defaultValue) {
        try {
            return Double.valueOf(getValue(key));
        } catch (NoSuchElementException ex) {
            return defaultValue;
        }
    }

    /**
     * 获取指定属性键对应的short基本类型的属性值。
     * @param key 属性键。
     * @return 属性键对应的short类型的属性值。
     * @throws java.util.NoSuchElementException 如果指定的键不存在，将抛出此异常。
     */
    @Override
    public short getShortValue(String key) {
        return Short.parseShort(getValue(key));
    }

    /**
     * 获取指定属性键对应的short类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的short类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public short getShortValue(String key, short defaultValue) {
        return getShortValue(key, Short.valueOf(defaultValue)).shortValue();
    }

    /**
     * 获取指定属性键对应的Short类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的Short类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public Short getShortValue(String key, Short defaultValue) {
        try {
            return Short.valueOf(getValue(key));
        } catch (NoSuchElementException ex) {
            return defaultValue;
        }
    }

    /**
     * 获取指定属性键对应的boolean基本类型的属性值。
     * @param key 属性键。
     * @return 属性键对应的boolean类型的属性值。
     * @throws java.util.NoSuchElementException 如果指定的键不存在，将抛出此异常。
     */
    @Override
    public boolean getBooleanValue(String key) {
        return Boolean.parseBoolean(getValue(key));
    }

    /**
     * 获取指定属性键对应的boolean类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的boolean类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public boolean getBooleanValue(String key, boolean defaultValue) {
        return getBooleanValue(key, Boolean.valueOf(defaultValue)).booleanValue();
    }

    /**
     * 获取指定属性键对应的Boolean类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的Boolean类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public Boolean getBooleanValue(String key, Boolean defaultValue) {
        try {
            return Boolean.valueOf(getValue(key));
        } catch (NoSuchElementException ex) {
            return defaultValue;
        }
    }

    /**
     * 获取指定属性键对应的float基本类型的属性值。
     * @param key 属性键。
     * @return 属性键对应的float类型的属性值。
     * @throws java.util.NoSuchElementException 如果指定的键不存在，将抛出此异常。
     */
    @Override
    public float getFloatValue(String key) {
        return Float.parseFloat(getValue(key));
    }

    /**
     * 获取指定属性键对应的float类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的float类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public float getFloatValue(String key, float defaultValue) {
        return getFloatValue(key, Float.valueOf(defaultValue)).floatValue();
    }

    /**
     * 获取指定属性键对应的Float类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的Float类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public Float getFloatValue(String key, Float defaultValue) {
        try {
            return Float.valueOf(getValue(key));
        } catch (NoSuchElementException ex) {
            return defaultValue;
        }
    }

    /**
     * 获取指定属性键对应的BigInteger类型的属性值。
     * @param key 属性键。
     * @return 属性键对应的BigInteger类型的属性值。
     * @throws java.util.NoSuchElementException 如果指定的键不存在，将抛出此异常。
     */
    @Override
    public BigInteger getBigIntegerValue(String key) {
        return new BigInteger(getValue(key));
    }

    /**
     * 获取指定属性键对应的BigInteger类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的BigInteger类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public BigInteger getBigIntegerValue(String key, BigInteger defaultValue) {
        try {
            return getBigIntegerValue(key);
        } catch (NoSuchElementException ex) {
            return defaultValue;
        }
    }

    /**
     * 获取指定属性键对应的BigDecimal类型的属性值。
     * @param key 属性键。
     * @return 属性键对应的BigDecimal类型的属性值。
     * @throws java.util.NoSuchElementException 如果指定的键不存在，将抛出此异常。
     */
    @Override
    public BigDecimal getBigDecimalValue(String key) {
        return new BigDecimal(getValue(key));
    }

    /**
     * 获取指定属性键对应的BigDecimal类型的属性值。如果此属性值不存在，将返回指定的默认值。
     * @param key 属性键。
     * @param defaultValue 当指定键对应的属性值不存在时的默认属性值。
     * @return 属性键对应的BigDecimal类型的属性值。如果此属性值不存在，将返回指定的默认值。
     */
    @Override
    public BigDecimal getBigDecimalValue(String key, BigDecimal defaultValue) {
        try {
            return getBigDecimalValue(key);
        } catch (NoSuchElementException ex) {
            return defaultValue;
        }
    }

    //---- not implement abstract methods --------------------------------------
    /**
     * 加载属性文件。由子类实现。
     * @param filePath 属性文件的路径。
     * @throws java.io.IOException 加载属性文件异常。
     * @throws java.lang.IllegalArgumentException 如果输入流包含错误的Unicode转义序列。
     */
    protected abstract void doLoadProperties(String filePath) throws IOException;
}
